/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
 *
 */

import path from 'path';

import { expect } from '@jest/globals';
import fse from 'fs-extra';
import { x } from 'tar';

import { CommonConst } from '../../../../src/const/common-const.js';
import { initExecuteCommand, runHvigorAsync } from '../../common/common';
import {
  AbilityType,
  APIType,
  APIVersion,
  CaseLevel,
  IsEnable,
  LanguageType,
  ModuleTemplateType,
  RuntimeOSType,
  SDKType,
} from '../../plugins/project-builder/models/constants';
import { TestCaseBuilder } from '../../plugins/task-builder/task-case-builder';
import { ProjectBuildOption, TestCaseFun } from '../../plugins/task-builder/test-case';
import { TestTaskOptionBuilder } from '../../plugins/task-builder/test-task-option';

const projectBuilderOption: ProjectBuildOption = {
  template: {
    sdk: SDKType.Single,
    runtimeOS: RuntimeOSType.HarmonyOS,
    apiVersion: APIVersion.API11,
    apiType: APIType.STAGE,
    language: LanguageType.ArkTs,
    abilityType: AbilityType.Application,
    entryTemplateType: ModuleTemplateType.EmptyAbility,
  },
  modulesOption: {
    /**
     * 执行打包的 har 模块
     */
    baseHar: {
      runtimeOS: RuntimeOSType.HarmonyOS,
      apiVersion: APIVersion.API11,
      apiType: APIType.STAGE,
      language: LanguageType.ArkTs,
      abilityType: AbilityType.Application,
      moduleTemplateType: ModuleTemplateType.StaticLibrary,
    },
    /**
     * 执行打包的 hsp 模块
     */
    baseHsp: {
      runtimeOS: RuntimeOSType.HarmonyOS,
      apiVersion: APIVersion.API11,
      apiType: APIType.STAGE,
      language: LanguageType.ArkTs,
      abilityType: AbilityType.Application,
      moduleTemplateType: ModuleTemplateType.SharedLibrary,
    },
    /**
     * 被 baseHar 依赖的模块，版本号为默认的 1.0.0
     */
    har1:{
      runtimeOS: RuntimeOSType.HarmonyOS,
      apiVersion: APIVersion.API11,
      apiType: APIType.STAGE,
      language: LanguageType.ArkTs,
      abilityType: AbilityType.Application,
      moduleTemplateType: ModuleTemplateType.StaticLibrary,
    },
    /**
     * 被 baseHar 依赖的模块，版本号为参数化的 @param:version.har，预期是替换成 1.0.2
     */
    har2: {
      runtimeOS: RuntimeOSType.HarmonyOS,
      apiVersion: APIVersion.API11,
      apiType: APIType.STAGE,
      language: LanguageType.ArkTs,
      abilityType: AbilityType.Application,
      moduleTemplateType: ModuleTemplateType.StaticLibrary,
    },
    /**
     * 被 baseHar 依赖的本地 har 包，outside.har 置于 baseHar 模块目录外部，预期是打进 baseHar.har 的根目录中
     */
    outside: {
      runtimeOS: RuntimeOSType.HarmonyOS,
      apiVersion: APIVersion.API11,
      apiType: APIType.STAGE,
      language: LanguageType.ArkTs,
      abilityType: AbilityType.Application,
      moduleTemplateType: ModuleTemplateType.StaticLibrary,
    },
    /**
     * 被 baseHar 依赖的本地 hsp 包，inside-default.tgz 置于 baseHar 模块目录内部，预期是打进 baseHar.har 且保持原有的相对路径
     */
    inside: {
      runtimeOS: RuntimeOSType.HarmonyOS,
      apiVersion: APIVersion.API11,
      apiType: APIType.STAGE,
      language: LanguageType.ArkTs,
      abilityType: AbilityType.Application,
      moduleTemplateType: ModuleTemplateType.SharedLibrary,
    }
  },
};

const testCaseFun: TestCaseFun = async (project, taskConfig, record) => {
  const projectRootPath = project.projectRootPath();

  // 创建 parameterFile.json5
  fse.writeFileSync(
    path.resolve(projectRootPath, 'parameterFile.json5'),
    JSON.stringify({
      version: {
        base: '1.0.1',
        har2: '1.0.2',
        author: '999.0.0'
      },
      dep: {
        har1: './har1',
        har2: 'file:./har2',
        outside: 'file:./outside/build/default/outputs/default/outside.har',
        insideBaseHar: 'file:./baseHar/dir1/dir2/inside-default.tgz',
        insideBaseHsp: 'file:./baseHsp/dir1/dir2/inside-default.tgz',
      }
    }),
  );

  // 在工程级 oh-package.json5 新增 parameterFile 属性
  const projectOhPackageJsonPath = path.resolve(projectRootPath, CommonConst.OH_PACKAGE_JSON5);
  const projectOhPackageJson = fse.readJsonSync(projectOhPackageJsonPath);
  projectOhPackageJson.parameterFile = './parameterFile.json5';
  fse.writeJsonSync(projectOhPackageJsonPath, projectOhPackageJson);

  writeBaseModuleOhPackageJson(path.resolve(projectRootPath, 'baseHar', CommonConst.OH_PACKAGE_JSON5), '@param:dep.insideBaseHar');
  writeBaseModuleOhPackageJson(path.resolve(projectRootPath, 'baseHsp', CommonConst.OH_PACKAGE_JSON5), '@param:dep.insideBaseHsp');

  // 修改 har2 模块的 oh-package.json5
  const har2OhPackageJsonPath = path.resolve(projectRootPath, 'har2', CommonConst.OH_PACKAGE_JSON5);
  const har2OhPackageJson = fse.readJsonSync(har2OhPackageJsonPath);
  fse.writeJsonSync(har2OhPackageJsonPath, {
    ...har2OhPackageJson,
    version: '@param:version.har2',
  });

  // make module outside
  const assembleOutsideHarResult = await runHvigorAsync(
    projectRootPath,
    initExecuteCommand({
      mode: 'module',
      product: 'default',
      module: 'outside@default',
      tasks: 'assembleHar',
    }),
  );
  expect(assembleOutsideHarResult.stdout).toContain('BUILD SUCCESSFUL');

  // make module inside，并将 release 模式的产物 inside-default.tgz 移动至 baseHar/baseHsp 模块内部 /dir1/dir2/inside-default.tgz
  const assembleInsideHarResult = await runHvigorAsync(
    projectRootPath,
    initExecuteCommand({
      mode: 'module',
      product: 'default',
      module: 'inside@default',
      tasks: 'assembleHsp',
      buildMode: 'release'
    }),
  );
  expect(assembleInsideHarResult.stdout).toContain('BUILD SUCCESSFUL');
  fse.ensureDirSync(path.resolve(projectRootPath, 'baseHar', 'dir1/dir2'));
  fse.copyFileSync(
    path.resolve(projectRootPath, 'inside', 'build/default/outputs/default/inside-default.tgz'),
    path.resolve(projectRootPath, 'baseHar', 'dir1/dir2/inside-default.tgz'),
  );
  fse.ensureDirSync(path.resolve(projectRootPath, 'baseHsp', 'dir1/dir2'));
  fse.copyFileSync(
    path.resolve(projectRootPath, 'inside', 'build/default/outputs/default/inside-default.tgz'),
    path.resolve(projectRootPath, 'baseHsp', 'dir1/dir2/inside-default.tgz'),
  );

  // make module baseHar
  const assembleHarResult = await runHvigorAsync(
    projectRootPath,
    initExecuteCommand({
      mode: 'module',
      product: 'default',
      module: 'baseHar@default',
      tasks: 'assembleHar',
    }),
  );
  expect(assembleHarResult.stdout).toContain('BUILD SUCCESSFUL');

  // make module baseHsp
  const assembleHspResult = await runHvigorAsync(
    projectRootPath,
    initExecuteCommand({
      mode: 'module',
      product: 'default',
      module: 'baseHsp@default',
      tasks: 'assembleHsp',
    }),
  );
  expect(assembleHspResult.stdout).toContain('BUILD SUCCESSFUL');

  validBuildResult(
    path.resolve(projectRootPath, 'baseHar', 'build/default/outputs/default/baseHar.har'),
    path.resolve(projectRootPath, '.temp_baseHar'),
  );
  validBuildResult(
    path.resolve(projectRootPath, 'baseHsp', 'build/default/outputs/default/baseHsp.har'),
    path.resolve(projectRootPath, '.temp_baseHsp'),
  );
};

function writeBaseModuleOhPackageJson(ohPackageJsonPath: string, insideValue: string) {
  const ohPackageJson = fse.readJsonSync(ohPackageJsonPath);
  fse.writeJsonSync(ohPackageJsonPath, {
    ...ohPackageJson,
    version: '@param:version.base',
    author: '@param:version.author',
    dependencies: {
      har1: '@param:dep.har1',
    },
    devDependencies: {
      har2: '@param:dep.har2',
    },
    dynamicDependencies: {
      outside: '@param:dep.outside',
      inside: insideValue,
    }
  });
}

function validBuildResult(harFilePath: string, unzipDir: string) {
  fse.ensureDirSync(unzipDir);
  x({ file: harFilePath, cwd: unzipDir, sync: true });

  // 检查解压后的 oh-package.json5
  const unzipOhPackageJson = fse.readJsonSync(path.resolve(unzipDir, 'package', CommonConst.OH_PACKAGE_JSON5));
  expect(unzipOhPackageJson.author).toBe('@param:version.author');
  expect(unzipOhPackageJson.version).toBe('1.0.1');
  expect(unzipOhPackageJson.dependencies.har1).toBe('1.0.0');
  expect(unzipOhPackageJson.devDependencies.har2).toBe('1.0.2');
  expect(unzipOhPackageJson.dynamicDependencies.inside).toBe('file:dir1/dir2/inside-default.tgz');
  expect(unzipOhPackageJson.dynamicDependencies.outside).toBe('file:outside.har');

  // 检查 inside-default.tgz 和 outside.har 是否有打进 baseHar.har 里面
  expect(fse.existsSync(path.resolve(unzipDir, 'package', 'dir1/dir2/inside-default.tgz'))).toBe(true);
  expect(fse.existsSync(path.resolve(unzipDir, 'package', 'outside.har'))).toBe(true);
}

TestCaseBuilder.builder()
  .caseName('parameterFile.test.ts')
  .description('本地依赖参数化')
  .projectBuilderOption(projectBuilderOption)
  .taskConfig(TestTaskOptionBuilder.builder().caseLevel(CaseLevel.AR).ohpmInstall(IsEnable.Enable).build())
  .testFun(testCaseFun)
  .load();
